/*
 * $Id: PagePanel.java,v 1.3 2009-01-26 05:09:01 tomoke Exp $
 *
 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package icraf.carbon.gui.pdf;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ImageObserver;

import javax.swing.JPanel;

import com.sun.pdfview.PDFPage;

/**
 * A Swing-based panel that displays a PDF page image. If the zoom tool is in
 * use, allows the user to select a particular region of the image to be zoomed.
 */
public class PagePanel extends JPanel implements ImageObserver {
	private static final long serialVersionUID = -3147255634794082563L;
	/** The image of the rendered PDF page being displayed */
	private Image currentImage;
	/** The current PDFPage that was rendered into currentImage */
	private PDFPage currentPage;
	/** The horizontal offset of the image from the left edge of the panel */
	private int offx;
	/** The vertical offset of the image from the top of the panel */
	private int offy;
	/** the current clip, in device space */

	// /** a listener for page changes */
	// PageChangeListener listener;
	/** a flag indicating whether the current page is done or not. */
	private Flag flag = new Flag();
	private double zoomScale = 1;
	private int pageWidthDef = 800;

	// Color boxcolor= new Color(255,200,200);
	/**
	 * Create a new PagePanel, with a default size of 800 by 600 pixels.
	 */
	public PagePanel() {
		super();
		setPreferredSize(new Dimension(800, 600));
		setFocusable(true);
		// addMouseListener(this);
		// addMouseMotionListener(this);
	}

	/**
	 * Stop the generation of any previous page, and draw the new one.
	 * 
	 * @param page
	 *            the PDFPage to draw.
	 */
	public synchronized void showPage(PDFPage page) {
		// stop drawing the previous page
		if (currentPage != null) {
			Dimension sz = getSize();
			currentPage.stop(sz.width, sz.height, null);
		}

		// set up the new page
		currentPage = page;
		if (page == null) {
			// no page
			currentImage = null;
			repaint();
		} else {

			// start drawing -- clear the flag to indicate we're in progress.
			flag.clear();
			// System.out.println("   flag cleared");

			Dimension sz = getSize();
			if (sz.width + sz.height == 0) {
				// no image to draw.
				return;
			}

			int w = (int) (pageWidthDef * zoomScale);
			Dimension pSize = page.getUnstretchedSize(w, w, null);
			currentImage = page.getImage(pSize.width, pSize.height, null, this);

			//if (pSize.width > sz.width || pSize.height > sz.height) {
			if(!pSize.equals(sz)) {
				this.setPreferredSize(pSize);
				revalidate();
			} else if (pSize.width < sz.width && pSize.height < sz.height) {
				if (!this.getParent().getSize().equals(sz)) {
					this.setPreferredSize(this.getParent().getSize());
					revalidate();
				}
			}

			repaint();

		}
	}

	/**
	 * Draw the image.
	 */
	public void paint(Graphics g) {
		Dimension sz = getSize();
		g.setColor(getBackground());
		g.fillRect(0, 0, getWidth(), getHeight());
		if (currentImage == null) {
			g.setColor(Color.black);
			g.drawString("No page selected", getWidth() / 2 - 30,
					getHeight() / 2);
		} else {
			// draw the image
			int imwid = currentImage.getWidth(null);
			int imhgt = currentImage.getHeight(null);
			// draw it centered within the panel
			offx = Math.max(0, (sz.width - imwid) / 2);
			offy = Math.max(0, (sz.height - imhgt) / 2);

			g.drawImage(currentImage, offx, offy, this);

		}

	}

	/**
	 * Gets the page currently being displayed
	 */
	public PDFPage getPage() {
		return currentPage;
	}

	/**
	 * Waits until the page is either complete or had an error.
	 */
	public void waitForCurrentPage() {
		flag.waitForFlag();
	}

	/**
	 * Handles notification of the fact that some part of the image changed.
	 * Repaints that portion.
	 * 
	 * @return true if more updates are desired.
	 */
	public boolean imageUpdate(Image img, int infoflags, int x, int y,
			int width, int height) {
		// System.out.println("Image update: " + (infoflags & ALLBITS));
		// Dimension sz = getSize();
		if ((infoflags & (SOMEBITS | ALLBITS)) != 0) {
			// [[MW: dink this rectangle by 1 to handle antialias issues]]
			repaint(x + offx, y + offy, width, height);
		}
		if ((infoflags & (ALLBITS | ERROR | ABORT)) != 0) {
			flag.set();
			// System.out.println("   flag set");
			return false;
		} else {
			return true;
		}
	}

	public void setZoom(double z) {
		Dimension d = this.getParent().getSize();
		int s = Math.min(d.width, d.height);
		if(z < 0 && pageWidthDef * zoomScale < s) {
			zoomScale =(double)s/ (double)pageWidthDef;
		}
		zoomScale += (zoomScale * z);
		zoomScale = Math.max(0.2, zoomScale);
		zoomScale = Math.min(4, zoomScale);
		showPage(currentPage);
	}
}
